import TextContent from "./textContent";
import { Props } from "src/types/shape";

interface textOption {
    text: string,
    length: number
}
export default class {
    props!: Props
    scene: any
    cursor!: HTMLElement | undefined
    textarea!: HTMLTextAreaElement | undefined
    addcanvasMouseUp!: Function //鼠标按下
    addKeyUp!: any //键盘抬起
    addKeyDown!: any //键盘按下起
    textContent!: TextContent
    textContentList: Array<TextContent> = []
    timeout!: NodeJS.Timeout //定时器
    private moveKey: Array<string> = ['ArrowRight', 'ArrowLeft', 'ArrowUp', 'ArrowDown', 'Home', 'End']//键盘移动
    constructor(scene: any) {
        this.scene = scene


    }
    /**
     * 打开
     */
    open(): void {
        const { domElement } = this.scene
        this.addcanvasMouseUp = this.canvasMousedown.bind(this)
        this.addKeyUp = this.keyUp.bind(this)
        this.addKeyDown = this.keyDown.bind(this)
        domElement.addEventListener('mouseup', this.addcanvasMouseUp)
        this.createCss()
    }
    /**
     * 画布按下
     * @param e MouseEvent
     */
    canvasMousedown(e: MouseEvent): void {
        this.props = this.initProps(e)
        this.textContent = new TextContent(this.props)
        this.textContentList.push(this.textContent)
        this.scene.add(this.textContent)
        this.createAuxiliary()
        this.textarea?.focus()
        this.setLineHeight('行高')
    }
    /**
     * 关闭
     */
    close(): void {
        const { domElement } = this.scene
        domElement.removeEventListener('mouseup', this.addcanvasMouseUp)
        this.removeCursor(this.cursor)
        this.removeTextarea(this.textarea)
    }
    /**
     * 创建辅助工具
     */
    createAuxiliary(): void {
        const { props, cursor, textarea, createCursor, createTextarea, updateTextareaPosition } = this
        if (cursor && textarea) {
            this.updateCursorPosition()
            updateTextareaPosition(textarea, props)
            textarea.value = ''
        } else {
            this.cursor = createCursor(props)
            this.textarea = createTextarea.bind(this)(props)
            this.textarea.addEventListener('keyup', this.addKeyUp)
            this.textarea.addEventListener('keydown', this.addKeyDown)
        }
    }
    /**
     * 创建光标
     * @param props 文字配置类
     * @returns HTMLElement 
     */
    createCursor(props: Props): HTMLElement {
        const { clientX, clientY, size } = props
        let div = document.createElement('DIV')
        div.style.position = 'absolute'
        div.style.left = clientX + 'px'
        div.style.top = clientY + 'px'
        div.style.width = 1 + 'px'
        div.style.height = (size + 2) + 'px'
        div.style.backgroundColor = 'black'
        div.className = 'cursor'
        document.body.appendChild(div)
        return div
    }
    /**
     * 创建输入框
     * @param props 文字配置类
     * @returns HTMLTextAreaElement
     */
    createTextarea(props: Props): HTMLTextAreaElement {
        const { clientX, clientY } = props
        let textarea = document.createElement('textarea')
        textarea.setAttribute("id", "myTextarea");
        textarea.style.cssText = `
        position:absolute;
        width:200px;height:100px;
        left:${clientX}px;
        top:${clientY + 50}px;
        opacity:0`
        document.body.appendChild(textarea)
        textarea.addEventListener('input', (e: any) => {
            this.fillterText(e.target.value)
        })
        return textarea
    }
    /**
     * 过滤文本框内容
     */
    fillterText(text: string | undefined) {
        if (!text) return []
        this.props.textObj = text.split('\n').map(item => {
            return [{ type: 'text', text: item, len: 0 }]
        })
    }
    /**
     * 更新光标位置
     */
    updateCursorPosition(): void {
        const { cursor, props } = this
        const { x, y } = this.getCaretPosition(this.textarea)

        if (cursor) {
            cursor.className = ''
            cursor.style.left = (props.clientX + x) + 'px'
            cursor.style.top = (props.clientY + y) + 'px'
            if (this.timeout) {
                clearTimeout(this.timeout)
            }
            this.timeout = setTimeout(() => {
                cursor.className = 'cursor'
            }, 500)
        }
    }
    /**
     * 更新文本框位置
     * @param textarea 文本框
     * @param props 文字配置类
     */
    updateTextareaPosition(textarea: HTMLTextAreaElement, props: Props): void {
        const { clientX, clientY } = props
        textarea.style.left = clientX + 'px'
        textarea.style.top = (clientY + 50) + 'px'
    }
    /**
     * 键盘按下
     * @param e any
     */
    keyDown(e: any): void {
        const { target, shiftKey, key } = e
        if (shiftKey && key == 'ArrowLeft') {
            //DOTO 选中未处理
            console.log('按下shift+left');
        }
        if (this.moveKey.includes(key)) {
            this.updateCursorPosition()
        } else {
            if (target)
                this.updateText(target.value || null)
        }

    }
    /**
     * 键盘抬起
     * @param e any
     */
    keyUp(e: any): void {
        const { target, key } = e
        if (this.moveKey.includes(key)) {
            this.updateCursorPosition()
        } else {
            this.updateText(target.value || null)
        }

    }
    /**
     * 删除光标
     * @param cursor 光标
     */
    removeCursor(cursor: HTMLElement | undefined): void {
        if (cursor) document.body.removeChild(cursor)
        this.cursor = undefined
    }
    /**
     * 删除文本框
     * @param textarea 文本框
     */
    removeTextarea(textarea: HTMLElement | undefined): void {
        if (textarea) document.body.removeChild(textarea)
        this.textarea = undefined
    }
    /**
     * 获取光标在文本中的位置
     * @param textarea 文本框
     * @returns x:当前文本宽度 y:当前行高度
     */
    getCaretPosition(textarea?: HTMLTextAreaElement): any {
        if (!textarea) return false
        let caretPos = 0;
        let lineNum = 1;
        let colNum = 1;
        if (textarea.selectionStart || textarea.selectionStart === 0) {
            caretPos = textarea.selectionStart;
        }
        let textLines = textarea.value.slice(0, caretPos).split('\n');
        this.updateWidthAndHeight(textLines)
        lineNum = textLines.length - 1;
        colNum = textLines[lineNum].length;
        let x = this.getTextWidth(textLines[lineNum].slice(0, colNum))
        let y = lineNum * this.props.lineHeight

        if (textarea.selectionStart != textarea.selectionEnd) {
            const a = textarea.value.slice(0, textarea.selectionStart)
            const b = textarea.value.slice(textarea.selectionStart, textarea.selectionEnd)
            const c = textarea.value.slice(textarea.selectionEnd)
            const d = (a + '<select>' + b + '</select>' + c).split('\n')
            let flag = false
            this.props.textObj = d.map(item => {
                const a1 = item.match('<select>')
                const a2 = item.match('</select>')
                const arr: any = []

                if (a1) {
                    flag = true
                }
                if (a1 && a2) {
                    const _a = item.split('<select>')
                    if (_a[0].length) arr.push({ type: 'text', text: _a[0] })
                    const _b = item.match(/\<select\>(\S*)\<\/select\>/)
                    if (_b) arr.push({ type: 'select', text: _b[1] })
                    const _c = item.split('</select>')
                    if (_c[1].length) arr.push({ type: 'text', text: _c[1] })
                    flag = false
                } else if (flag) {
                    if (a1) {
                        const _d = item.split('<select>')
                        if (_d[0]) arr.push({ type: 'text', text: _d[0] })
                        if (_d[1]) arr.push({ type: 'select', text: _d[1] })
                    } else if (a2) {
                        const _e = item.split('</select>')
                        if (_e[0]) arr.push({ type: 'select', text: _e[0] })
                        if (_e[1]) arr.push({ type: 'text', text: _e[1] })
                        flag = false
                    } else {
                        arr.push({ type: 'select', text: item })
                    }
                } else {
                    arr.push({ type: 'text', text: item })
                }
                let l = 0
                arr.forEach((item: any) => {
                    item.len = l
                    l += item.text.length
                })

                return arr
            })

            this.textContent.setProps(this.props)
        } else {
            this.fillterText(textarea.value)
            this.textContent.setProps(this.props)
        }
        return { x, y };
    }
    /**
     * 更新画布上的文本
     * @param value 输入框文本
     */
    updateText(value: string): void {
        const { text } = this.props
        if (value != text) {
            this.props.text = value
            this.textContent.setProps(this.props)
            this.updateCursorPosition()
            this.scene.render()
        }
    }
    /**
     * 测量文本宽度
     * @param text 需要测量的文本
     * @returns 文本宽度
     */
    getTextWidth(text: string): number {
        const { ctx } = this.scene
        const { size } = this.props
        if (!ctx) return 0
        ctx.font = `${size}px Arial`
        return ctx.measureText(text).width
    }
    /**
     * 设置行高
     * @param text 随便 根据当前size用canvas测量
     */
    setLineHeight(text: string): void {
        const { ctx } = this.scene
        const { size } = this.props
        ctx.font = `${size}px Arial`
        let metrics = ctx.measureText(text);
        // 当前文本字符串在这个字体下用的实际高度
        this.props.lineHeight = metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent;
    }
    /**
     * 设置光标闪烁样式
     */
    createCss(): void {
        //动态添加CSS
        var style = document.createElement('style');
        style.innerHTML = `
                    .cursor{
                        opacity:1;
                        animation: flicker .8s infinite;
                    }
                    @keyframes flicker{
                        50%{
                            opacity:0
                        }
                    }
                    `;
        document.head.appendChild(style);
    }
    /**
     * 更新影子高宽
     * @param textList 用换行截取后的文本数组
     */
    updateWidthAndHeight(textList: Array<string>): void {
        let option: textOption = { text: '', length: 0 };
        const { lineHeight } = this.props
        if (textList) {
            textList.map(item => {
                if (item.length > option.text.length) {
                    option.text = item
                }
            })
            this.props.width = this.getTextWidth(option.text)
            this.props.height = lineHeight * textList.length
        }
    }
    /**
     * 初始化文本配置
     * @param e MouseEvent
     * @returns 文本配置
     */
    initProps(e: MouseEvent): Props {
        const { domElement } = this.scene
        let props = new Props()
        props.id = String(Date.now())
        props.x = e.offsetX
        props.y = e.offsetY
        props.clientX = e.offsetX + domElement.offsetLeft
        props.clientY = e.offsetY + domElement.offsetTop
        return props
    }
}